class_name UnitMover
extends Node
## 版本：1.0.0
## 功能：PlayArea 中 Unit 的移动，即可以放置在 PlayArea 网格中，当移动到无效的位置时回到初始位置，放置时可以替换对象位置。
## 使用：挂载到 Node 节点上，配置 play_areas 和 dragged_units 导出变量。
## 前置：PlayArea。

#region Exported parameters
## 可以被拖拽到的游戏性区域
@export var play_areas: Array[PlayArea]

## 存放正在被拖拽的单元
@export var dragged_units: Node
#endregion


func setup_unit(unit: Unit) -> void:
	unit.drag_and_drop.drag_started.connect(_on_unit_drag_started.bind(unit))
	unit.drag_and_drop.drag_canceled.connect(_on_unit_drag_canceled.bind(unit))
	unit.drag_and_drop.dropped.connect(_on_unit_dropped.bind(unit))


func _get_first_available_play_area() -> PlayArea:
	for play_area: PlayArea in play_areas:
		if play_area.unit_grid.has_empty_cell():
			return play_area
	return null


func _get_play_area_from_world_global_position(world_global_position: Vector2) -> PlayArea:
	for play_area in play_areas:
		var cell_position := play_area.get_cell_position_from_world_global_position(world_global_position)
		if play_area.unit_grid.is_cell_in_grid(cell_position):
			return play_area
	return null


func _reset_unit_to_start_global_position(unit: Unit, start_global_position: Vector2) -> void:
	var play_area := _get_play_area_from_world_global_position(start_global_position)
	assert(play_area, "Error")
	
	var cell_position := play_area.get_cell_position_from_world_global_position(start_global_position)
	
	# 在返回原始位置时，也需要考虑位置是或否被占用了
	if not play_area.unit_grid.is_cell_empty(cell_position):
		# 原先位置被占用，寻找新的空余位置
		play_area = _get_first_available_play_area()
		assert(play_area, "Error")
		
		cell_position = play_area.unit_grid.get_first_empty_cell_position()
	
	assert(play_area.add_unit_to_empty_cell(unit, cell_position), "Error")


func _on_unit_drag_started(unit: Unit) -> void:
	var play_area := _get_play_area_from_world_global_position(unit.global_position)
	assert(play_area, "Error")
	
	play_area.remove_unit(unit)
	dragged_units.add_child(unit)


func _on_unit_drag_canceled(start_global_position: Vector2, unit: Unit) -> void:
	_reset_unit_to_start_global_position(unit, start_global_position)


func _on_unit_dropped(start_global_position: Vector2, unit: Unit) -> void:
	var mouse_global_position := unit.get_global_mouse_position()

	var old_area := _get_play_area_from_world_global_position(start_global_position)
	assert(old_area, "Error")
	
	var old_cell_position := old_area.get_cell_position_from_world_global_position(start_global_position)
	
	var new_area := _get_play_area_from_world_global_position(mouse_global_position)
	# 拖拽到无效区域了，返回原始位置
	if not new_area:
		_reset_unit_to_start_global_position(unit, start_global_position)
		return
	
	var new_cell_position := new_area.get_cell_position_from_world_global_position(mouse_global_position)
	
	# 如果释放拖拽的单元格不为空单元格
	if not new_area.add_unit_to_empty_cell(unit, new_cell_position):
		var orignal_unit = new_area.unit_grid.get_unit(new_cell_position)
		
		# 替换对象
		assert(new_area.remove_unit_from_cell_position(new_cell_position), "Error")
		assert(old_area.add_unit_to_empty_cell(orignal_unit, old_cell_position), "Error")
		assert(new_area.add_unit_to_empty_cell(unit, new_cell_position), "Error")
